Dart 语法入门 I

代码示例

// 定义一个方法
printNumber(num aNumber) {
  print('The number is $aNumber.');
}

// 主函数
main() {
  var number = 42;
  printNumber(number); // The number is 42
}

重要概念 Important concepts

  • 所有变量都可以看作对象 (object),每个对象都是一个类的实例。
    包括 numbers、function 和 null 都是对象。所有对象都继承自 Object 类。
  • 指定静态类型(比如代码示例中的 num)表明你想指定的变量用途。(未指定具体类型的变量在 debug 时会发现被指定为一个特殊的类型:dynamic)
    为确保代码类型安全,查看 稳定模式 Dart
  • Dart 在运行前会解析所有代码。你可以先准备几点,比如使用类型和编译常量来捕获 errors 或者使代码运行更快。
  • Dart 支持顶层方法,比如 main()。也可以绑定在一个类或者对象上(分别为静态和实例方法)。也可以在方法中定义方法。
  • 同理,Dart 也支持顶层变量,并且可以绑定到类或对象(静态和实例变量)。实例变量也称作字段或者属性。
  • 不同于 Java,Dart 没有关键字 public、protected 和 private。如果一个标识符以下划线 _ 开头,则它的库使私有的。详见 库和可见性
  • 标识符以字母和下划线 _ 开头,接着字母和数字的任意组合
  • Dart 工具可以报告两种问题:警告 Warnings 和错误 errors。
  • Dart 有两种运行模式:生产 (production) 和检查 (checked)。一般在检查模式开发和调试,最终部署到生产模式
  • Production mode 是 Dart 程序一个速度优化的默认运行模式。Production mode 忽略断言语句(assert statements)和静态类型
  • Checked mode 是开发人员友好的方式,可以帮助你在运行时捕捉一些类型的错误。例如,如果分配一个非数字来声明为一个 num 变量,然后在检查模式会抛出异常

变量 Variables

var name = 'Voyager I';
var year = 1977;
var antennaDiameter = 3.7;
var flybyObjects = ['Jupiter', 'Saturn', 'Uranus', 'Neptune'];
var image = {
  'tags': ['saturn'],
  'url': '//path/to/saturn.jpg'
};

默认值

未初始化的变量值为 null,即使指定了数字类型也是 null,因为 numbers 也是对象。

int lineCount;
assert(lineCount == null);
// Variables (even if they will be numbers) are initially null.
// assert(condition) 方法只在检查模式下有用,表达式的值或者函数返回 true,则 assert 语句成功并继续执行代码。如果值为 false,则 assert 语句失败并抛出一个异常 (AssertionError)

final 和 const

一个 final 变量只能设定一次且不能更改,一个 const 变量是编译时变量(const 变量是隐式 final 变量)。
一个 final 的顶层变量或者类变量,会在它第一次被调用时初始化。

final name = 'Bob'; // Or: final String name = 'Bob';
name = 'Alice';  // Uncommenting this causes an error
// [] 创建一个空数组,const [] 创建一个不可变空数组 (EIA)
var foo = const [];   // foo 当前是 EIA
final bar = const []; // bar 一直是 EIA
const baz = const []; // baz 是编译时的 EIA

// 可以改变非 final、const 定义的变量,即使它之前是赋的 const 值,比如 foo
foo = [];

// 但 bar、baz 不能更改

可选的静态类型

变量类型包括:numbers、strings、booleans、lists(也就是数组)、maps、runs、symbols。
每个变量类型有自定义的构造函数,比如 new Map() 创建一个 map 变量。

数字类型 numbers 分 int(-2e53 ~ 2e53)和 double 型(IEEE 754 标准), 支持 abs()、ceil() 等 math 函数
int 型支持位运算,如<<、>>、& 和 |

// 类型转换
// String -> int
var one = int.parse('1');
assert(one == 1);

// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);

// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');

// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');

字符串类型 Strings

Strings 是 UTF-16 代码单元的序列,可以使用单引号或双引号创建一个字符串。

可以通过使用 ${expression} 把一个表达式的值放进字符串。如果表达式是一个标识符,你可以跳过{}。为了获得相应对象的字符串,Dart 调用对象的 toString()方法。

var s = 'string interpolation';

assert('Dart has $s, which is very handy.' ==
       'Dart has string interpolation, ' +
       'which is very handy.'); // true
assert('That deserves all caps. ' +
       '${s.toUpperCase()} is very handy!' ==
       'That deserves all caps. ' +
       'STRING INTERPOLATION is very handy!'); // true

可以利用相邻字符串或 + 运算符连接字符串:

var s1 = 'String ' 'concatenation'
         " works even over line breaks.";
assert(s1 == 'String concatenation works even over '
             'line breaks.'); // true

var s2 = 'The + operator '
         + 'works, as well.';
assert(s2 == 'The + operator works, as well.'); //true

使用三个单或双引号创建一个多行字符串

var s1 = '''
You can create
multi-line strings like this one.
''';

var s2 = """This is also a multi-line string.""";

带有 r 的前缀来创建一个“raw”的字符串

var s = r"In a raw string, even \n isn't special.";

支持 Unicode 转义

print('Unicode escapes work: \u2665');

布尔类型 booleans

不同于 javaScript,1、“aString”、someObject 都视为假的

var name = 'Bob';
if (name) {
  // JavaScript 中会产生打印,而 Dart 中不会
  print('in javaScript, You have a name!');
} else {
  print('but in Dart, print this line')
}
// 在 Dart 生产模式下,上述条件为假;而在检查模式下,程序会抛出一个异常,因为 name 类型不是 bool
if (1) {
  print('JS prints this line.');
} else {
  print('Dart in production mode prints this line.');
  // 但在 checked 模式下会抛出一个异常,因为 1 不是一个 boolean
}

Dart 的判断条件应该指定为布尔类型,不能使用 if(nonbooleanValue),这个在检查模式下会抛出异常

// 检查一个空字符串.
var fullName = '';
assert(fullName.isEmpty);

// 检查为零.
var hitPoints = 0;
assert(hitPoints <= 0);

// 检查是否为空.
var unicorn;
assert(unicorn == null);

// 检查 NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);

列表类型 List

在 Dart,数组是列表对象,所以我们通常只是将其称为 lists。
常见用法与 javaScript 类似:

var fruits = ['apples', 'oranges']; // 也可以用构造函数 new List('apples', 'oranges')
// 如果指定类型, new List<String>('apples') 或者<String>['apples'] 则只能存放字符类型, 否则在检查模式下加入非指定类型元素会抛出异常

fruits.add('kiwis'); // 添加元素

fruits.addAll(['grapes', 'bananas']); // 添加多个元素

assert(fruits.length == 5); // 获取长度

fruits.forEach((item) => print('I have some $item')) // forEach((key, value) => {}) 可以传两个参数

fruits.map((item) => print('I have some $item'))

fruits.where((item) => item === 'oranges') // where() 筛选符合条件的元素

// 删除一个元素
var appleIndex = fruits.indexOf('apples');
fruits.removeAt(appleIndex);
assert(fruits.length == 4);

// 清空列表
fruits.clear();
assert(fruits.length == 0);

更多用法详见 泛型 Generics集合 Collections

Maps 类型

一般情况下,map 是一个键值对组成的对象,这两个键和值可以是任何类型的对象。

var gifts = {
  'first' : 'partridge',
  'second': 'turtledoves',
  'fifth' : 'golden rings'
};

var nobleGases = {
  2 :   'helium',
  10:   'neon',
  18:   'argon',
};

/* ----- 也可以使用构函数 ----- */
var gifts = new Map();
gifts['first'] = 'partridge'; // 直接添加键值对
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

var nobleGases = new Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';

assert(nobleGases.length == 3) // length 返回 map 中键值对的数目

// 创建一个编译时常量
final constantMap = const {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};
constantMap[2] = 'Helium'; // 会报错,因为不可更改

Runes 符号类型

在 Dart 中,runes 是字符串的 UTF-32 点。Unicode 给每个字符定义了一个值。因为 Dart 中的字符串是 UTF-16 单元的序列,所以表达 32 位 Unicode 值需要特定的语法来实现。
通常一个 Unicode 码的形式是 /uXXXX,XXXX 是 4 位 16 进制的值,比如 \u2665 代表 ♥ 这个符号,当指定多于或少于 4 位的 16 进制时用{}包裹,比如 \u{1f600}代表 😆 这个符号。
字符串的属性方法中 codeUnitAt 和 codeUnit 返回 16 位代码单元,runes 属性方法用于获取 String 类型的 runes 值:

main() {
  var clapping = '\u{1f44f}';
  print(clapping);
  print(clapping.codeUnits);
  print(clapping.runes.toList());

  Runes input = new Runes(
      '\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}');
  print(new String.fromCharCodes(input));
}
// 输出结果
👏
[55357, 56399]
[128079]
♥  😅  😎  👻  🖖  👍

符号类型 symbols

一个符号对象表示在 Dart 程序中声明的操作符或标识。你可能不会需要使用这些符号,但他们对于由名字指向的 API 是很有用的,因为时常要改变的是标识符的名字,而不是标识符的符号。

为了得到符号的标识,使用符号的文本,只是#后跟标识符:

#radix
#bar

更多详细信息见 Dart: mirrors—reflection

文章目录
  1. 代码示例
  2. 重要概念 Important concepts
  3. 变量 Variables
    1. 默认值
    2. final 和 const
    3. 可选的静态类型
    4. 字符串类型 Strings
    5. 布尔类型 booleans
    6. 列表类型 List
    7. Maps 类型
    8. Runes 符号类型
    9. 符号类型 symbols